import 'dart:convert';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:dio_http_cache/dio_http_cache.dart';
import 'package:flutter/material.dart';
import 'package:flutterapp/common/constant/api.dart';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:flutterapp/common/util/log_utils.dart';
import 'package:flutterapp/common/util/toast_utils.dart';
import 'package:flutterapp/http/def_json_factory.dart';
import 'package:flutterapp/http/head_interceptor.dart';
import 'package:flutterapp/http/logger_interceptor.dart';
import 'package:path_provider/path_provider.dart';

/// Http工具类
///
/// dio的使用参考 https://github.com/flutterchina/dio/blob/master/README-ZH.md
///
class HttpUtils {
  static HttpUtils? _instance;
  late Dio _dio;
  late DioCacheManager _dioCacheManager;
  late CookieManager _cookieManager;

  //单一实例方法
  static HttpUtils getInstance() {
    if (_instance == null) _instance = HttpUtils._();
    return _instance!;
  }

  /// 构造器初始化配置在此内进行
  HttpUtils._() {
    initConfig();
  }

  /// 初始化配置
  Future initConfig() async {
    // 或者通过传递一个 `options`来创建dio实例
    BaseOptions options = BaseOptions()
      ..baseUrl = API.baseUrl
      ..connectTimeout = 5000
      ..receiveTimeout = 3000;

    _dio = Dio(options);

    _dioCacheManager = DioCacheManager(CacheConfig(baseUrl: API.baseUrl));

    _cookieManager = await getCookieInterceptor();

    //添加拦截器
    _dio.interceptors
      //请求头管理拦截器
      ..add(HeadInterceptor())
      //cookie管理拦截器
      ..add(_cookieManager)
      //缓存管理拦截器
      ..add(_dioCacheManager.interceptor)
      //日志管理拦截器
      ..add(LoggerInterceptor());
  }

  ///获取cookie拦截器
  ///
  ///[needLocalSave] 是否需要本地保存cookie
  Future<CookieManager> getCookieInterceptor(
      [bool needLocalSave = true]) async {
    try {
      if (needLocalSave) {
        //cookie持久化，保存在文件中,用户手动销毁
        Directory appDocDir = await getApplicationDocumentsDirectory();
        String appDocPath = appDocDir.path;
        PersistCookieJar _cookieJar =
            PersistCookieJar(storage: FileStorage("$appDocPath\/cookies/"));
        return CookieManager(_cookieJar);
      } else {
        //默认cookie拦截器，将cookie保存在运存中，应用退出cookie销毁
        return CookieManager(CookieJar());
      }
    } catch (e, s) {
      LogUtils.e('获取cookie拦截器发生错误!', e, s);
      return CookieManager(CookieJar());
    }
  }

  /// post 请求方法
  Future<T?> post<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    bool isNeedCache = false,
    void Function(int, int)? onSendProgress,
    void Function(int, int)? onReceiveProgress,
    void Function(T)? onSuccess,
    void Function(String)? onResult,
    Function(Object, StackTrace)? onFailure,
    bool showErrorToast = true,
  }) {
    return _request<T>(
      path,
      data: data,
      queryParameters: queryParameters,
      options: options == null ? Options(method: 'POST') : options
        ..method = 'POST',
      cancelToken: cancelToken,
      isNeedCache: isNeedCache,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
      onSuccess: onSuccess,
      onResult: onResult,
      onFailure: onFailure,
    );
  }

  /// get 请求方法
  Future<T?> get<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    bool isNeedCache = false,
    void Function(int, int)? onSendProgress,
    void Function(int, int)? onReceiveProgress,
    void Function(T)? onSuccess,
    void Function(String)? onResult,
    Function(Object, StackTrace)? onFailure,
    bool showErrorToast = true,
  }) {
    return _request<T>(
      path,
      data: data,
      queryParameters: queryParameters,
      options: options == null ? Options(method: 'GET') : options
        ..method = 'GET',
      cancelToken: cancelToken,
      isNeedCache: isNeedCache,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
      onSuccess: onSuccess,
      onResult: onResult,
      onFailure: onFailure,
    );
  }

  /// post 请求方法,有返回值，会将请求结果返回
  ///
  /// [path] 路径
  ///
  /// [queryParameters] 请求参数
  ///
  /// [options] 请求配置
  ///
  /// [cancelToken] 请求token，可以来关闭请求(请谨慎使用)
  ///
  /// [isNeedCache] 是否需要缓存
  ///
  /// [onSendProgress] 发送进度的回调方法
  ///
  /// [onReceiveProgress] 接收进度的回调方法
  ///
  /// [onSuccess] 返回结果成功回调，返回值为指定的类型
  ///
  /// [onResult] 返回结果成功回调,返回值为字符串
  ///
  /// [onFailure] 失败回调
  ///
  /// [showErrorToast] 显示错误的吐丝提示，默认显示
  ///
  Future<T?> _request<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    bool isNeedCache = false,
    void Function(int, int)? onSendProgress,
    void Function(int, int)? onReceiveProgress,
    void Function(T)? onSuccess,
    void Function(String)? onResult,
    Function(Object, StackTrace)? onFailure,
    bool showErrorToast = true,
  }) async {
    try {
      //是否需要缓存配置
      var optionTemp = isNeedCache
          ? buildCacheOptions(Duration(days: 7),
              maxStale: Duration(days: 10), subKey: "page=1", options: options)
          : options;
      //开始请求
      Response response = await _dio.request(
        path,
        data: data,
        queryParameters: queryParameters,
        options: optionTemp,
        cancelToken: cancelToken,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress,
      );

      //将结果以字符串的型式抛出
      onResult?.call(response.toString());

      //json转化
      T t = DefaultJsonFactory.getInstance()
          .onResponse<T>(json.decode(response.toString()));

      //将成功的响应抛出
      onSuccess?.call(t);

      //将解析结果抛出
      return t;
    } catch (error, stackTrace) {
      //打印请求报错信息
      LogUtils.e(error);

      //显示吐丝提示
      if (showErrorToast) shortToast(handleError(error));

      //将失败的响应抛出
      onFailure?.call(
        handleError(error),
        stackTrace,
      );

      return null;
    }
  }

  /// 处理错误
  String handleError(e) {
    if (e is! DioError) return e.toString();
    String errorMsg = "";
    switch (e.type) {
      case DioErrorType.connectTimeout:
        errorMsg = "连接超时";
        break;
      case DioErrorType.receiveTimeout:
        errorMsg = "接收超时";
        break;
      case DioErrorType.sendTimeout:
        errorMsg = "发送超时";
        break;
      case DioErrorType.cancel:
        errorMsg = "请求取消";
        break;
      case DioErrorType.response:
        errorMsg = "服务器状态码错误";
        break;
      case DioErrorType.other:
        errorMsg = e.message;
        break;
      default:
        errorMsg = e.message;
        break;
    }

    return errorMsg;
  }

  /// 显示加载对话框
  void showProgressDialog(BuildContext context, String content) {
    showDialog(
        context: context,
        builder: (context) {
          return UnconstrainedBox(
            constrainedAxis: Axis.vertical,
            child: SizedBox(
              width: 280,
              child: AlertDialog(
                content: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: <Widget>[
                    CircularProgressIndicator(
                      value: .8,
                    ),
                    Padding(
                      padding: const EdgeInsets.only(top: 26.0),
                      child: Text(content),
                    )
                  ],
                ),
              ),
            ),
          );
        });
  }

  ///清除缓存
  Future<bool> clearAllCache() async {
    //清理所有缓存不管有没有过期
    return _dioCacheManager.clearAll();

//    //清理过期的缓存
//    _dioCacheManager.clearExpired()
  }

  /// 清除cookie
  clearAllCookie() {
    _cookieManager.cookieJar.deleteAll();
  }
}
